#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "qt_server.h"
#include "myds.h"
#include "msg_pack.h"
#include "mysqlite3.h"
#include "my_hashmap.h"

hashmap_t *map;
static int epfd;
static int serverfd;
extern int waitUeserResp;

bool handleLogin(msg_pack_t *pack, int clientfd)
{
    char *userid = pack_getField(pack, 0)->content;
    char *pwd = pack_getField(pack, 1)->content;
    // printf("userid=[%s], pwd=[%s]\n", userid, pwd);
    // 数据库查询
    sqlite3 *db = mysql_getConn();
    int ret = mysql_user_exit(db, userid, pwd);
    mysql_closeConn(db);
    // printf("数据库查询结果 ret=[%d]\n", ret);
    // 返回报文
    msg_pack_t *packRet = pack_create(PACK_LOGIN_RET);
    pack_add_field(packRet, 4, (char *)&ret);
    // 发送
    char *buf = (char *)malloc(sizeof(char) * packRet->totalLen);
    pack_2_buf(packRet, buf);
    ssize_t cnt = send(clientfd, buf, packRet->totalLen, 0);
    // printf("已经向网路发送[%ld]字节数据\n", cnt);
    // 释放资源
    pack_destroy(pack);
    pack_destroy(packRet);
    free(buf);
    // printf("资源释放完成\n");
    return true;
}

bool handleReg(msg_pack_t *pack, int clientfd)
{
    // 数据库查询
    sqlite3 *db = mysql_getConn();
    my_user_t user;
    memcpy(user.userid, pack_getField(pack, 0)->content, pack_getField(pack, 0)->filedLen);
    memcpy(user.pwd, pack_getField(pack, 1)->content, pack_getField(pack, 1)->filedLen);
    int ret = mysql_user_add(db, &user);
    mysql_closeConn(db);
    // printf("数据库查询结果 ret=[%d]\n", ret);

    // 返回报文
    msg_pack_t *packRet = pack_create(PACK_REG_RET);
    pack_add_field(packRet, 4, (char *)&ret);

    // 发送
    char *buf = (char *)malloc(sizeof(char) * packRet->totalLen);
    pack_2_buf(packRet, buf);
    ssize_t cnt = send(clientfd, buf, packRet->totalLen, 0);
    // printf("已经向网路发送[%ld]字节数据\n", cnt);
    // 释放资源
    pack_destroy(pack);
    pack_destroy(packRet);
    free(buf);
    // printf("资源释放完成\n");
    return true;
}

bool handleDevList(msg_pack_t *pack, int clientfd)
{
    // 数据库查询
    sqlite3 *db = mysql_getConn();
    char userid[20] = {0};
    memcpy(userid, pack_getField(pack, 0)->content, pack_getField(pack, 0)->filedLen);
    my_dev_t devList[20];
    int devNums = 0;
    int ret = mysql_dev_list(db, userid, devList, &devNums); // 查询
    mysql_closeConn(db);
    // printf("数据库查询结果 ret=[%d],devNums=[%d]\n", ret, devNums);

    // 返回报文
    msg_pack_t *packRet = pack_create(PACK_DEVLIST_RET);
    pack_add_field(packRet, 4, (char *)&ret);
    for (int i = 0; i < devNums; i++)
    {
        my_dev_t dev = devList[i];
        // printf("devname=[%s][%ld],devid=[%s][%ld]\n", dev.devname, strlen(dev.devname), dev.devid, strlen(dev.devid));
        pack_add_field(packRet, strlen(dev.devname) + 1, dev.devname);
        pack_add_field(packRet, strlen(dev.devid) + 1, dev.devid);
        // TODO 通过devid查询MAP，看装置是否在线
        data_t* data = hashmap_get(map, dev.devid);
        if(data == NULL || data->devid <=0){
            pack_add_field(packRet, strlen("离线") + 1, "离线");    
        }else{
            pack_add_field(packRet, strlen("在线") + 1, "在线");
        }
        pack_add_field(packRet, strlen(dev.desc) + 1, dev.desc);
    }

    // 发送
    char *buf = (char *)malloc(sizeof(char) * packRet->totalLen);
    pack_2_buf(packRet, buf);
    // for (int i = 0; i < 40; i++)
    //     printf("%02X ", (unsigned char)buf[i]);
    // printf("\n");
    ssize_t cnt = send(clientfd, buf, packRet->totalLen, 0);
    // printf("已经向网路发送[%ld]字节数据\n", cnt);
    // 释放资源
    pack_destroy(pack);
    pack_destroy(packRet);
    free(buf);
    // printf("资源释放完成\n");
    return true;
}

bool handleDevAdd(msg_pack_t *pack, int clientfd)
{
    // 数据库查询
    sqlite3 *db = mysql_getConn();

    my_dev_t dev;
    memcpy(dev.userid, pack_getField(pack, 0)->content, pack_getField(pack, 0)->filedLen);
    memcpy(dev.devid, pack_getField(pack, 1)->content, pack_getField(pack, 1)->filedLen);
    memcpy(dev.devname, pack_getField(pack, 2)->content, pack_getField(pack, 2)->filedLen);
    memcpy(dev.desc, pack_getField(pack, 3)->content, pack_getField(pack, 3)->filedLen);

    int ret = mysql_dev_add(db, &dev);

    mysql_closeConn(db);
    // 返回报文
    msg_pack_t *packRet = pack_create(PACK_DEV_ADD_RET);
    pack_add_field(packRet, 4, (char *)&ret);

    // 发送
    char *buf = (char *)malloc(sizeof(char) * packRet->totalLen);
    pack_2_buf(packRet, buf);
    ssize_t cnt = send(clientfd, buf, packRet->totalLen, 0);
    printf("已经向网路发送[%ld]字节数据\n", cnt);
    // 释放资源
    pack_destroy(pack);
    pack_destroy(packRet);
    free(buf);
    printf("资源释放完成\n");
    return true;
}

bool handleDevDel(msg_pack_t *pack, int clientfd)
{
    // 数据库查询
    sqlite3 *db = mysql_getConn();

    char userid[20], devid[20];
    memcpy(userid, pack_getField(pack, 0)->content, pack_getField(pack, 0)->filedLen);
    memcpy(devid, pack_getField(pack, 1)->content, pack_getField(pack, 1)->filedLen);

    int ret = mysql_dev_del(db, userid, devid);

    mysql_closeConn(db);
    // 返回报文
    msg_pack_t *packRet = pack_create(PACK_DEV_DEL_RET);
    pack_add_field(packRet, 4, (char *)&ret);

    // 发送
    char *buf = (char *)malloc(sizeof(char) * packRet->totalLen);
    pack_2_buf(packRet, buf);
    ssize_t cnt = send(clientfd, buf, packRet->totalLen, 0);
    // printf("已经向网路发送[%ld]字节数据\n", cnt);
    // 释放资源
    pack_destroy(pack);
    pack_destroy(packRet);
    free(buf);
    // printf("资源释放完成\n");
    return true;
}

bool handleStartCamera(msg_pack_t *pack, int clientfd)
{
    // 获取userid和devid
    char userid[20] = {0}, devid[20] = {0};
    memcpy(userid, pack_getField(pack, 0)->content, pack_getField(pack, 0)->filedLen);
    memcpy(devid, pack_getField(pack, 1)->content, pack_getField(pack, 1)->filedLen);
    // 判断对应的dev是否在线
    data_t *data = hashmap_get(map, devid);
    int ret = 1;
    if (data == NULL || data->devfd <= 0)
    { // 设备不在线
        ret = 0;
    }
    else
    {
        // 更新hash表
        data->userfd = clientfd;
        hashmap_printself(map);
        // hashmap_printself(map);
        // 转发开始命令
        char *buf = (char *)malloc(sizeof(char) * pack->totalLen);
        pack_2_buf(pack, buf);
        ssize_t cnt = send(data->devfd, buf, pack->totalLen, 0);
        // printf("已经向设备转发[%ld]字节数据\n", cnt);
        free(buf);
    }
    // 回复报文用户端
    msg_pack_t *packRet = pack_create(PACK_START_CAMERA_RET); // 返回报文
    pack_add_field(packRet, 4, (char *)&ret);
    char *buf = (char *)malloc(sizeof(char) * packRet->totalLen);
    pack_2_buf(packRet, buf);
    ssize_t cnt = send(clientfd, buf, packRet->totalLen, 0);
    // printf("已经向网路发送[%ld]字节数据\n", cnt);
    // 释放资源
    pack_destroy(pack);
    pack_destroy(packRet);
    free(buf);
    // printf("资源释放完成\n");
    printf("start Camera CMD  222:: !!!!!!");
    hashmap_printself(map);
    return true;
}

bool handleStopCamera(msg_pack_t *pack, int clientfd)
{
    printf("关闭远程摄像头指令!!!!!\n");
    // 获取userid和devid
    char userid[20] = {0}, devid[20] = {0};
    memcpy(userid, pack_getField(pack, 0)->content, pack_getField(pack, 0)->filedLen);
    memcpy(devid, pack_getField(pack, 1)->content, pack_getField(pack, 1)->filedLen);
    // 判断对应的dev是否在线
    data_t *data = hashmap_get(map, devid);
    int ret = 0;
    if (data != NULL && data->devfd > 0)
    {
        // 转发开始命令
        char *buf = (char *)malloc(sizeof(char) * pack->totalLen);
        pack_2_buf(pack, buf);
        ssize_t cnt = send(data->devfd, buf, pack->totalLen, 0);
        // printf("已经向设备转发[%ld]字节数据\n", cnt);
        free(buf);
        ret = 1;
    }
    // 回复报文用户端
    msg_pack_t *packRet = pack_create(PACK_STOP_CAMERA_RET); // 返回报文
    pack_add_field(packRet, 4, (char *)&ret);
    char *buf = (char *)malloc(sizeof(char) * packRet->totalLen);
    pack_2_buf(packRet, buf);
    ssize_t cnt = send(clientfd, buf, packRet->totalLen, 0);
    // printf("已经向网路发送[%ld]字节数据\n", cnt);
    // 释放资源
    pack_destroy(pack);
    pack_destroy(packRet);
    free(buf);
    // printf("资源释放完成\n");
    return true;
}

bool handleVideoRet(msg_pack_t *pack, int clientfd)
{
    waitUeserResp = 1;//收到了回复
    pack_destroy(pack);
    return true;
}

bool recvHandle(int clientfd)
{
    msg_pack_t *pack = pack_from_socket(clientfd);
    if (pack == NULL)
    {
        return false;
    }
    bool ret;
    // 根据不同的报文类型，处理报文
    switch (pack->type)
    {
    case PACK_LOGIN:
        return handleLogin(pack, clientfd);
    case PACK_REG:
        return handleReg(pack, clientfd);
    case PACK_DEVLIST:
        return handleDevList(pack, clientfd);
    case PACK_DEV_ADD:
        return handleDevAdd(pack, clientfd);
    case PACK_DEV_DEL:
        return handleDevDel(pack, clientfd);
    case PACK_START_CAMERA:
        return handleStartCamera(pack, clientfd);
    case PACK_STOP_CAMERA:
        return handleStopCamera(pack, clientfd);
    case PACK_DEV_VEDIO_RET:
        return handleVideoRet(pack, clientfd);
    default:
        break;
    }

    return true;
}

void *qt_server_task(void *args)
{
    while (1)
    {
        struct epoll_event events[50];
        int len = epoll_wait(epfd, events, 50, -1);
        for (int i = 0; i < len; i++)
        {
            struct epoll_event e = events[i];
            int fd = e.data.fd;
            if (fd == serverfd)
            { // 新的tcp连接
                struct sockaddr_in addr;
                int addrlen;
                printf("[%s]新的客户端连接\n", __func__);
                int clientfd = accept(serverfd, (struct sockaddr *)&addr, &addrlen);
                struct epoll_event event = {.events = EPOLLIN, .data.fd = clientfd};
                epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, &event);
                printf("[%s]新的客户端连接 clientfd=[%d]\n", __func__, clientfd);
            }
            else
            { // 客户端消息
                printf("[%s]收到来自客户端[%d]的消息\n", __func__, fd);
                if (!recvHandle(fd))
                {
                    printf("[%s]断开连接，客户端fd=[%d]\n", __func__, fd);
                    close(fd);
                    epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
                }
            }
        }
    }
}

bool qt_server_init(char *hostname, int port)
{
    map = hashmap_create();
    //
    serverfd = socket(AF_INET, SOCK_STREAM, 0);
    printf("[%s] socket: serverfd=[%d]\n", __func__, serverfd);
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr(hostname);
    if (bind(serverfd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
    {
        printf("[%s]端口bind失败\n", __func__);
        return false;
    }
    //
    if (listen(serverfd, 50) != 0)
    {
        printf("[%s]listen失败\n", __func__);
        return false;
    }
    //
    epfd = epoll_create(50);
    printf("[%s] epoll_create: epfd=[%d],server=[%d]\n", __func__, epfd, serverfd);
    struct epoll_event event = {.events = EPOLLIN, .data.fd = serverfd};
    epoll_ctl(epfd, EPOLL_CTL_ADD, serverfd, &event);
    //
    pthread_t tid;
    pthread_create(&tid, NULL, qt_server_task, NULL);
    pthread_detach(tid);
    //
    return true;
}